package com.northpool.operator.transfer.merge;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.FileUtil;
import com.northpool.operator.annotation.InputParam;
import com.northpool.operator.annotation.InputParams;
import com.northpool.operator.annotation.OperatorInfo;
import com.northpool.operator.common.algorithm.OperatorTestBuild;
import com.northpool.operator.common.algorithm.TestParamBuilder;
import com.northpool.operator.common.stpclient.StpClientOperatorBase;
import com.northpool.operator.param.ParamTool;
import com.northpool.operator.type.TypeEnum;
import com.northpool.resources.datasource.ogr.FGDBDataSource;
import com.northpool.resources.datatable.ITable;
import com.northpool.stpclient.bean.BaseResponse;
import com.northpool.stpclient.bean.datatransfer.TableCopyBuildPlan;
import com.northpool.stpclient.bean.datatransfer.TbaleCopyModeEnum;
import com.northpool.stpclient.modules.geoprocess.datatransfer.IDataTransferOperator;

import java.io.File;
import java.util.concurrent.CompletableFuture;

@OperatorInfo(ref = "GdbAppenderOperator", name = "Gdb合并")
public class GdbAppenderOperator extends StpClientOperatorBase {

    @InputParams({
            @InputParam(ref = "folderPath", name = "文件夹路径", required = true, desc = "文件夹下多个gdb数据源文件夹，如: /data/gis"),
            @InputParam(ref = "targetFgdb", name = "目标Fgdb路径", required = true, desc = "合并后输出的Fgdb数据源文件夹路径，如: /data/gis/target.gdb"),
            @InputParam(ref = "timeout", name = "单次任务超时时间", type = TypeEnum.NUMBER, value = "600", desc = "执行一次合并子任务的超时时间，单位为秒，如: 600")
    })
    public GdbAppenderOperator() {
    }

    public static void main(String[] args) throws Exception {
        OperatorTestBuild.execute(GdbAppenderOperator.class, TestParamBuilder.aBuilder()
                .param("folderPath", "D:\\data\\GisData\\1b100w")
                .param("targetFgdb", "D:\\data\\GisData\\1b100w_result.gdb")
                .param("timeout", "6000")
                .build());
    }

    @Override
    public void execute(ParamTool paramTool) throws Exception {
        String folderPath = paramTool.getStr("folderPath");
        String targetFgdb = paramTool.getStr("targetFgdb");
        long timeout = paramTool.getNumber("timeout").longValue();

        boolean exist = FileUtil.exist(targetFgdb);
        if (exist) {
            this.log("目标Fgdb数据源已存在, 请更换目标文件夹");
            this.failedExit();
        }
        IDataTransferOperator transferOperator = this.client.dataTransferOperator();
        FGDBDataSource targetDataSource = new FGDBDataSource(targetFgdb);
        targetDataSource.create(); // 创建目标数据源

        File[] files = FileUtil.ls(folderPath);
        for (File file : files) {
            boolean directory = file.isDirectory();
            if (!directory) {
                this.log("跳过文件: {}", file.getName());
                continue;
            }
            if (!file.getName().endsWith(".gdb")) {
                this.log("跳过文件夹: {}", file.getName());
                continue;
            }

            FGDBDataSource ds = new FGDBDataSource(file.getAbsolutePath());
            try {
                ds.testConnection(); // 测试连接
                ds.destroy();
            } catch (Exception ex) {
                this.error("读取Fgdb数据源失败: {}", ExceptionUtil.getMessage(ex));
                this.error("跳过Fgdb数据源: {}", file.getAbsolutePath());
                continue;
            }

            String[] tables = ds.tables();
            for (String tableName : tables) {
                // 创建合并任务
                ITable table = ds.getTable(tableName);
                Integer srid = table.spatialInfo().getSrid();

                TableCopyBuildPlan plan = TableCopyBuildPlan.TableCopyParamsBuilder.create()
                        .addSrid(srid)
                        // 设置来源数据源
                        .addOriginDatasource(ds)
                        // 设置来源表
                        .addOriginTableName(tableName)
                        // 设置目标数据源
                        .addTargetDatasource(targetDataSource)
                        // 设置目标表名
                        .addTargetTableName(tableName)
                        .addMode(TbaleCopyModeEnum.APPENDER)
                        .build();

                BaseResponse response = transferOperator.startTableCopy(plan);
                String requestId = response.getRequestId();
                CompletableFuture<BaseResponse> future = new CompletableFuture<>();
                transferOperator.onStart(requestId, () -> {
                    this.log("开始合并：{}|{}", file.getAbsolutePath(), tableName);
                });
                transferOperator.onError(requestId, () -> {
                    String log = transferOperator.log(requestId);
                    this.log("合并失败：{}, 图层：{}", file.getAbsolutePath(), tableName);
                    this.log("----------------异常日志开始----------------");
                    this.log(log);
                    this.log("----------------异常日志结束----------------");
                    future.completeExceptionally(new RuntimeException("任务失败: " + requestId));
//                    future.complete(response);
                });
                transferOperator.onSuccess(requestId, () -> {
                    future.complete(response);
                });
                future.get();
            }
        }
        this.successExit();
    }
}
